/*****************************************************************************
 *   Copyright 2005 Tim A Wang
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 *
 ****************************************************************************/
package com.jb.web.bean;

import com.jb.faces.component.ActionSource;
import com.jb.faces.context.FacesContext;
import com.jb.faces.el.MethodBinding;
import com.jb.faces.event.ActionEvent;
import com.jb.faces.event.ActionListener;
import com.jb.faces.event.FacesEvent;
import com.jb.faces.event.PhaseId;
import com.jb.framework.PersistentContext;
import com.jb.util.ClassUtil;
import com.jb.web.application.Command;
import com.jb.web.context.WebContext;

import java.util.ArrayList;


public class Link extends Text implements ActionSource, Command, ValueHolder {
    static final long serialVersionUID = 123123L;

    static {
        publish(com.jb.web.bean.Link.class, GENERAL, "disabled");
        publish(com.jb.web.bean.Link.class, GENERAL, "title");
        publish(com.jb.web.bean.Link.class, GENERAL, "destination");
        publish(com.jb.web.bean.Link.class, EVENT_HANDLER, "onCommand");
    }

    private ArrayList listeners = new ArrayList();
    private MethodBinding action;
    private MethodBinding actionListener;
    private String defaultAction;
    private String defaultListener;
    private String destination = null;
    private boolean disabled;
    private boolean immediate;

    public Link() {
        super();
    }

    public Link(Label text) {
        super();
        assign(text);
    }

    public void setAction(MethodBinding action) {
        this.action = action;
    }

    public MethodBinding getAction() {
        if (action == null) {
            action = createDefaultMethodBinding(defaultAction);
        }

        return action;
    }

    public void setActionListener(MethodBinding actionListener) {
        this.actionListener = actionListener;
    }

    public MethodBinding getActionListener() {
        if ((actionListener == null) && (defaultListener != null)) {
            actionListener = createDefaultMethodBinding(defaultListener);
        }

        return actionListener;
    }

    public ActionListener[] getActionListeners() {
        ActionListener[] actionListeners = new ActionListener[listeners.size()];

        for (int i = 0; i < actionListeners.length; i++) {
            actionListeners[i] = (ActionListener) listeners.get(i);
        }

        return actionListeners;
    }

    //implement command interface
    public String getCommand() {
        return getClientId();
    }

    public void setDefaultAction(String defaultAction) {
        this.defaultAction = defaultAction;
    }

    public String getDefaultAction() {
        return defaultAction;
    }

    public void setDefaultListener(String defaultListener) {
        this.defaultListener = defaultListener;
    }

    public String getDefaultListener() {
        return defaultListener;
    }

    public void setDestination(String destination) {
        this.destination = destination;
    }

    public String getDestination() {
        return destination;
    }

    public void setDisabled(boolean disabled) {
        this.disabled = disabled;
    }

    public boolean isDisabled() {
        return disabled;
    }

    public void setImmediate(boolean immediate) {
        this.immediate = immediate;
    }

    public boolean isImmediate() {
        return immediate;
    }

    public void setOnCommand(String command) {
        this.setOnUpdateModel(command);
    }

    public String getOnCommand() {
        return getOnUpdateModel();
    }

    public void addActionListener(ActionListener listener) {
        //
        //only add if it does not exist. We do not add it twice
        //
        if (listeners.indexOf(listener) == -1) {
            listeners.add(listener);
        }
    }

    public void broadcast(FacesEvent event)  {
        ActionListener[] listeners = getActionListeners();

        for (int i = 0; i < listeners.length; i++) {
            event.processListener(listeners[i]);
        }

        if (defaultListener != null) {
            getActionListener().invoke(getFacesContext(), new Object[] { event });
        }

        if (getFacesContext().getApplication().getActionListener() != null) {
            event.processListener(getFacesContext().getApplication().getActionListener());
        }
    }

    public void processDecodes(FacesContext ctx) {
        super.processDecodes(ctx);
        WebContext webContext = (WebContext) ctx;
        if (isMyEvent(webContext)) {
            if(log.isDebugEnabled())
                log.debug("queneEvent "+this);
            queueEvent(new ActionEvent(this));
        }
    }

    public boolean execute(PersistentContext ctx) {
        return true;
    }

    public void queueEvent(FacesEvent e) {
        super.queueEvent(e);

        if ((e instanceof ActionEvent) && immediate) {
            e.setPhaseId(PhaseId.APPLY_REQUEST_VALUES);
        }
    }

    public void removeActionListener(ActionListener listener) {
        listeners.remove(listener);
    }

    protected void init() {
        super.init();
        setValue("Link");
    }

    private MethodBinding createDefaultMethodBinding(final String className) {
        if (className == null) {
            return null;
        }

        MethodBinding methodBinding = new MethodBinding() {
                Class mClass;

                public Object invoke(FacesContext ctx, java.lang.Object[] param2) {
                    return null;
                }

                public Class getType(FacesContext ctx) {
                    
                    if (mClass == null) {
                        mClass = ClassUtil.getClass(className);
                    }

                    return mClass;
                }
            };

        return methodBinding;
    }
}
